using Huatuo.Generators;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using UnityEditor;
using UnityEditor.Build.Player;
using UnityEngine;
using FileMode = System.IO.FileMode;

namespace Huatuo
{
    /// <summary>
    /// 这里仅仅是一个流程展示
    /// 简单说明如果你想将huatuo的dll做成自动化的简单实现
    /// </summary>
    public class EditorHelper
    {
        private static void CreateDirIfNotExists(string dirName)
        {
            if (!Directory.Exists(dirName))
            {
                Directory.CreateDirectory(dirName);
            }
        }

        private static string ToRelativeAssetPath(string s)
        {
            return s.Substring(s.IndexOf("Assets/"));
        }

        public static string DllBuildOutputDir => Path.GetFullPath($"{Application.dataPath}/../Temp/Huatuo/build");

        public static string GetDllBuildOutputDirByTarget(BuildTarget target)
        {
            return $"{DllBuildOutputDir}/{target}";
        }

        [MenuItem("Huatuo/CompileDll/ActiveBuildTarget")]
        public static void CompileDllActiveBuildTarget()
        {
            var target = EditorUserBuildSettings.activeBuildTarget;
            CompileDll(GetDllBuildOutputDirByTarget(target), target);
        }

        [MenuItem("Huatuo/CompileDll/Win64")]
        public static void CompileDllWin64()
        {
            var target = BuildTarget.StandaloneWindows64;
            CompileDll(GetDllBuildOutputDirByTarget(target), target);
        }

        [MenuItem("Huatuo/CompileDll/Linux64")]
        public static void CompileDllLinux()
        {
            var target = BuildTarget.StandaloneLinux64;
            CompileDll(GetDllBuildOutputDirByTarget(target), target);
        }

        [MenuItem("Huatuo/CompileDll/OSX")]
        public static void CompileDllOSX()
        {
            var target = BuildTarget.StandaloneOSX;
            CompileDll(GetDllBuildOutputDirByTarget(target), target);
        }

        [MenuItem("Huatuo/CompileDll/Android")]
        public static void CompileDllAndroid()
        {
            var target = BuildTarget.Android;
            CompileDll(GetDllBuildOutputDirByTarget(target), target);
        }

        [MenuItem("Huatuo/CompileDll/IOS")]
        public static void CompileDllIOS()
        {
            var target = BuildTarget.iOS;
            CompileDll(GetDllBuildOutputDirByTarget(target), target);
        }

        private static void CompileDll(string buildDir, BuildTarget target)
        {
            var group = BuildPipeline.GetBuildTargetGroup(target);
            ScriptCompilationSettings scriptCompilationSettings = new ScriptCompilationSettings();
            scriptCompilationSettings.group = group;
            scriptCompilationSettings.target = target;
            CreateDirIfNotExists(buildDir);
            ScriptCompilationResult scriptCompilationResult =
                PlayerBuildInterface.CompilePlayerScripts(scriptCompilationSettings, buildDir);
            foreach (var ass in scriptCompilationResult.assemblies)
            {
                Debug.LogFormat("compile assemblies:{0}", ass);
            }
        }

        public static string HuatuoBuildCacheDir => $"{Application.dataPath}/HuatuoBuildCache";

        public static string AssetBundleOutputDir => $"{HuatuoBuildCacheDir}/AssetBundleOutput";

        public static string AssetBundleSourceDataTempDir => $"{HuatuoBuildCacheDir}/AssetBundleSourceData";

        public static string HuatuoDataDir => $"{Application.dataPath}/../HuatuoData";

        public static string AssembliesPostIl2CppStripDir => $"{HuatuoDataDir}/AssembliesPostIl2CppStrip";

        public static string HuatuoIl2CppDir => $"{HuatuoDataDir}/LocalIl2CppData/il2cpp";

        public static string MethodBridgeCppDir =>
            $"{HuatuoDataDir}/LocalIl2CppData/il2cpp/libil2cpp/huatuo/interpreter"; 

        [MenuItem("Huatuo/BuildBundles/ActiveBuildTarget")]
        public static void BuildSeneAssetBundleActiveBuildTarget()
        {
            var target = EditorUserBuildSettings.activeBuildTarget;
            BuildAssetBundles(GetAssetBundleTempDirByTarget(target), GetAssetBundleOutputDirByTarget(target), target);
        }

        [MenuItem("Huatuo/BuildBundles/Win64")]
        public static void BuildSeneAssetBundleWin64()
        {
            var target = BuildTarget.StandaloneWindows64;
            BuildAssetBundles(GetAssetBundleTempDirByTarget(target), GetAssetBundleOutputDirByTarget(target), target);
        }

        [MenuItem("Huatuo/BuildBundles/OSX")]
        public static void BuildSeneAssetBundleOSX64()
        {
            var target = BuildTarget.StandaloneOSX;
            BuildAssetBundles(GetAssetBundleTempDirByTarget(target), GetAssetBundleOutputDirByTarget(target), target);
        }

        [MenuItem("Huatuo/BuildBundles/Linux64")]
        public static void BuildSeneAssetBundleLinux64()
        {
            var target = BuildTarget.StandaloneLinux64;
            BuildAssetBundles(GetAssetBundleTempDirByTarget(target), GetAssetBundleOutputDirByTarget(target), target);
        }

        [MenuItem("Huatuo/BuildBundles/Android")]
        public static void BuildSeneAssetBundleAndroid()
        {
            var target = BuildTarget.Android;
            BuildAssetBundles(GetAssetBundleTempDirByTarget(target), GetAssetBundleOutputDirByTarget(target), target);
        }

        [MenuItem("Huatuo/BuildBundles/IOS")]
        public static void BuildSeneAssetBundleIOS()
        {
            var target = BuildTarget.iOS;
            BuildAssetBundles(GetAssetBundleTempDirByTarget(target), GetAssetBundleOutputDirByTarget(target), target);
        }

        private static string GetAssetBundleOutputDirByTarget(BuildTarget target)
        {
            return $"{AssetBundleOutputDir}/{target}";
        }

        private static string GetAssetBundleTempDirByTarget(BuildTarget target)
        {
            return $"{AssetBundleSourceDataTempDir}/{target}";
        }

        /// <summary>
        /// 将HotFix.dll和HotUpdatePrefab.prefab打入common包.
        /// 将HotUpdateScene.unity打入scene包.
        /// </summary>
        /// <param name="tempDir"></param>
        /// <param name="outputDir"></param>
        /// <param name="target"></param>
        private static void BuildAssetBundles(string tempDir, string outputDir, BuildTarget target)
        {
            //todo 搞定资源加载后处理这一部分
            
            // CreateDirIfNotExists(tempDir);
            // CreateDirIfNotExists(outputDir);
            //
            // var notSceneAssets = new List<string>();
            //
            // CompileDll(GetDllBuildOutputDirByTarget(target), target);
            //
            // var hotfixDlls = new List<string>()
            // {
            //     "HotFix.dll",
            //     "HotFix2.dll",
            // };
            //
            // foreach (var dll in hotfixDlls)
            // {
            //     var dllPath = $"{GetDllBuildOutputDirByTarget(target)}/{dll}";
            //     var dllBytesPath = $"{tempDir}/{dll}.bytes";
            //     File.Copy(dllPath, dllBytesPath, true);
            //     notSceneAssets.Add(dllBytesPath);
            // }
            //
            // var aotDlls = new string[]
            // {
            //     "mscorlib.dll",
            //     "System.dll",
            //     "System.Core.dll", // 如果使用了Linq，需要这个
            // };
            //
            // string aotDllDir = $"{AssembliesPostIl2CppStripDir}/{target}";
            // foreach (var dll in aotDlls)
            // {
            //     string dllPath = $"{aotDllDir}/{dll}";
            //     if (!File.Exists(dllPath))
            //     {
            //         Debug.LogError(
            //             $"ab中添加AOT补充元数据dll:{dllPath} 时发生错误,文件不存在。裁剪后的AOT dll在BuildPlayer时才能生成，因此需要你先构建一次游戏App后再打包。");
            //         continue;
            //     }
            //
            //     string dllBytesPath = $"{tempDir}/{dll}.bytes";
            //     File.Copy(dllPath, dllBytesPath, true);
            //     notSceneAssets.Add(dllBytesPath);
            // }
            //
            // string testPrefab = $"{Application.dataPath}/Prefabs/HotUpdatePrefab.prefab";
            // notSceneAssets.Add(testPrefab);
            // AssetDatabase.Refresh(ImportAssetOptions.ForceUpdate);
            //
            //
            // List<AssetBundleBuild> abs = new List<AssetBundleBuild>();
            // AssetBundleBuild notSceneAb = new AssetBundleBuild
            // {
            //     assetBundleName = "common",
            //     assetNames = notSceneAssets.Select(s => ToRelativeAssetPath(s)).ToArray(),
            // };
            // abs.Add(notSceneAb);
            //
            //
            // string testScene = $"{Application.dataPath}/Scenes/HotUpdateScene.unity";
            // string[] sceneAssets =
            // {
            //     testScene,
            // };
            // AssetBundleBuild sceneAb = new AssetBundleBuild
            // {
            //     assetBundleName = "scene",
            //     assetNames = sceneAssets.Select(s => s.Substring(s.IndexOf("Assets/"))).ToArray(),
            // };
            //
            // abs.Add(sceneAb);
            //
            // BuildPipeline.BuildAssetBundles(outputDir, abs.ToArray(), BuildAssetBundleOptions.None, target);
            //
            // AssetDatabase.Refresh(ImportAssetOptions.ForceUpdate);
            //
            // string streamingAssetPathDst = $"{Application.streamingAssetsPath}";
            // CreateDirIfNotExists(streamingAssetPathDst);
            //
            // foreach (var ab in abs)
            // {
            //     AssetDatabase.CopyAsset(ToRelativeAssetPath($"{outputDir}/{ab.assetBundleName}"),
            //         ToRelativeAssetPath($"{streamingAssetPathDst}/{ab.assetBundleName}"));
            // }
        }

        [MenuItem("Huatuo/Generate/MethodBridge_X64")]
        public static void MethodBridge_X86()
        {
            string outputFile = $"{MethodBridgeCppDir}/MethodBridge_x64.cpp";
            var g = new MethodBridgeGenerator(new MethodBridgeGeneratorOptions()
            {
                CallConvention = CallConventionType.X64,
                Assemblies = AppDomain.CurrentDomain.GetAssemblies().ToList(),
                OutputFile = outputFile,
            });

            g.PrepareMethods();
            g.Generate();
            Debug.LogFormat("== output:{0} ==", outputFile);
            CleanIl2CppBuildCache();
        }

        [MenuItem("Huatuo/Generate/MethodBridge_Arm64")]
        public static void MethodBridge_Arm64()
        {
            string outputFile = $"{MethodBridgeCppDir}/MethodBridge_arm64.cpp";
            var g = new MethodBridgeGenerator(new MethodBridgeGeneratorOptions()
            {
                CallConvention = CallConventionType.Arm64,
                Assemblies = AppDomain.CurrentDomain.GetAssemblies().ToList(),
                OutputFile = outputFile,
            });

            g.PrepareMethods();
            g.Generate();
            Debug.LogFormat("== output:{0} ==", outputFile);
            CleanIl2CppBuildCache();
        }
        
        private static void CleanIl2CppBuildCache()
        {
            string il2cppBuildCachePath = $"{Application.dataPath}/../Library/Il2cppBuildCache";
            if (!Directory.Exists(il2cppBuildCachePath))
            {
                return;
            }

            Debug.Log($"clean il2cpp build cache:{il2cppBuildCachePath}");
            Directory.Delete(il2cppBuildCachePath, true);
        }
    }
}